package com.gitee.hermer.boot.jee.io.activemq;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.Session;
import org.apache.activemq.command.ActiveMQObjectMessage;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.beans.factory.annotation.Autowired;

import com.gitee.hermer.boot.jee.commons.dict.BootProperties;
import com.gitee.hermer.boot.jee.commons.log.UtilsContext;
import com.gitee.hermer.boot.jee.commons.utils.JsonUtils;
import com.gitee.hermer.boot.jee.commons.utils.StringUtils;

/**
 * 
 * @author tumc
 *
 * @param <T>
 */
public abstract class ActiveMQBeanSuperService<T extends Serializable> extends UtilsContext implements MessageListener,ExceptionListener {

	
	private String packageName;
	
	protected String toJSON(T t) {
		return JsonUtils.toJSONString(t);
	}

	protected T fromJSON(String json,Class<Serializable> clz) {
		return (T) JsonUtils.fromJSONToBean(json, clz);
	}
	protected T fromJSON(String json) {
		return fromJSON(json,getSuperClassGenricType(getClass(), 0));
	}

	@Autowired
	protected ActiveMQExecute activeMQExecute;
	
	@Autowired
	private BootProperties properties;

	public enum SendMQEvent{
		QUEUE(".Queue"),
		TOPIC(".Topic");
		String sign = null;
		SendMQEvent(String sign){
			this.sign = sign;
		}
		public String getSign(){
			return sign;
		}
	}
	@Override
	public void onException(JMSException arg0) {
		error(arg0.getMessage(),arg0);
	}

	

	/**
	 * 用来命名MQName
	 * @return
	 */
	public abstract String getName();

	public String getQueueSignName(){
		return packageName+ StringUtils.capitalize(getName()) + SendMQEvent.QUEUE.getSign();
	}
	public String getTopicSignName(){
		return packageName+ StringUtils.capitalize(getName()) + SendMQEvent.TOPIC.getSign();
	}

	@Override 
	public final void onMessage(Message arg0) {
		SendMQEvent event = null;
		Session session = null;
		try {
			ActiveMQObjectMessage message = ((ActiveMQObjectMessage)arg0);
			event = arg0.getJMSDestination() instanceof ActiveMQQueue ?SendMQEvent.QUEUE:SendMQEvent.TOPIC;
			if(event == SendMQEvent.QUEUE)
				session = activeMQExecute.getSessionQueue();
			else
				session = activeMQExecute.getSessionTopic();
			@SuppressWarnings("unchecked")
			T t = fromJSON((String)message.getObject());
			
			debug("Receive message:Consumer["+(event==SendMQEvent.QUEUE?getQueueSignName():getTopicSignName())+"] - "+toJSON(t));
			onMessage(event,session,t);
			session.commit();
		} catch (Exception e) {
			try {
				session.rollback();
			} catch (JMSException e1) {
				error(e1.getMessage(),e1);
			}
			error(e.getMessage(),e);


		}
	}
	/**
	 * 消费者接收方法 
	 * @param t
	 */
	public abstract void onMessage(SendMQEvent event,Session session,T t) throws Exception;

	@PreDestroy
	public void destroy(){
		activeMQExecute.closeConnectionListener();
	}

	@PostConstruct
	public void init(){
		try {
			activeMQExecute.queueMessageListener(getQueueSignName(), this,this);
			activeMQExecute.topicMessageListener(getTopicSignName(), this,this);
			packageName = properties.getDictValueString("wms.mq.package");

		} catch (Exception e) {
			error(e.getMessage(),e);
		}
	}	

	public void sendTopicMsg(T t){
		try {
			activeMQExecute.sendTopicMsg(getTopicSignName(), toJSON(t));

			debug("Send message:Consumer["+getTopicSignName()+"] - "+toJSON(t));
		} catch (JMSException e) {
			error(e.getMessage(),e);
		}
	}

	public void sendQueueMsg(T t){
		try {
			activeMQExecute.sendQueueMsg(getQueueSignName(), toJSON(t));
			debug("Send message:Consumer["+getQueueSignName()+"] - "+toJSON(t));
		} catch (JMSException e) {
			error(e.getMessage(),e);
		}
	}

	@SuppressWarnings("unchecked")  
	protected  Class<Serializable> getSuperClassGenricType(final Class clazz, final int index) {  
		Type genType = clazz.getGenericSuperclass();  
		if (!(genType instanceof ParameterizedType)) {  
			return Serializable.class;  
		}  
		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();  

		if (index >= params.length || index < 0) {  
			return Serializable.class;  
		}  
		if (!(params[index] instanceof Class)) {  
			return Serializable.class;  
		}  

		return (Class) params[index];  
	}  

}
